import { exec, prepareVNodeForRanking, assign, pathRankSort } from './util';

//存放Router对象组件的数组
const ROUTERS = [];
const Subscribers = [];


function route(url, replace=false) {
	if (typeof url!=='string' && url.url) {
		replace = url.replace;
		url = url.url;
	}
	return routeTo(url);
}


/** 告诉所有路由器实例来处理给定的URL  */
function routeTo(url) {
	// ROUTERS是存放Router组件的数组
	for (let i=0; i<ROUTERS.length; i++) {
		ROUTERS[i].navigateTo(url);
	}
}

//link的调用
function lineventArt(url){
	console.log(Subscribers);
	// 处理路由变化的函数,Subscribers是放link组件的数组
	for (let i=Subscribers.length; i--; ) {
		Subscribers[i].selectenev(url);
	}
}







//过滤按钮链接
function routeFromLink(node) {
	if (!node || !node.getAttribute) return;
	let href = node.getAttribute('href'), target = node.getAttribute('target');
	if (!href || !href.match(/^\//g) || (target && !target.match(/^_?self$/i))) return;
	return route(href);
}







//关键函数，从children列表中找到可与url匹配的vnode,键名为url, 键值为path属性为url的vnode
function getMatchingChildren(children, url, invoke=true) {
	return children
		.filter(prepareVNodeForRanking)
		.sort(pathRankSort)
		.map( vnode => {
			//这里exec执行后，如果匹配返回匹配节点的props，否则返回false
			let matches = exec(url, vnode[1].path, vnode[1]);
			if (matches) {
				if (invoke !== false) {
					//复制一个新组件，将url和匹配节点的props都拷贝过去当做新对象的props
					return Reactor.cloneOf(vnode, assign({url}, matches));
				}
				//对于不需要新组件的情况，直接返回原来的组件
				return vnode;
			}
			//如果没有匹配的，就不返回，在下一步过滤中会被过滤掉
		}).filter(Boolean); //移除所有的“false”类型元素(false, null, undefined, 0, NaN or an empty string)
}


//处理链接点击事件
function handleLinkClick(e) {
	// 鼠标左键点击
	if (e.ctrlKey || e.metaKey || e.altKey || e.shiftKey || e.buttons!==0) return;
	routeFromLink(e.currentTarget || e.target || this);   
	return prevent(e);
}
//阻止默认行为
function prevent(e) {
	if (e) {
		if (e.stopImmediatePropagation) e.stopImmediatePropagation();
		if (e.stopPropagation) e.stopPropagation();
		e.preventDefault();
	}
	return false;
}







//Router 组件
class Router extends Element {
    routeView;
	this(props, kids){
        this.url = props.url;   //必须要有一个初始url，这样才知道默认加载哪一个
		this.kids = kids;
		this.onChange = props.onChange;     //回调函数留着扩展备用
		this.routeView = getMatchingChildren(this.kids,this.url)[0];   
		this.mypath =this.routeView? this.routeView[1].path:"未匹配到";
		
			
	}


    
      // 加载成功后，将当前路由对象加入ROUTERS
	componentDidMount() {
		ROUTERS.push(this);
		lineventArt(this.mypath);   //发送信息给link,让它高亮，因为菜单渲染的快，加载渲染的慢，必须在后面
	}
	// 当前router析构以后，将当前路由从对象ROUTERS中删除掉
	componentWillUnmount() {
		ROUTERS.splice(ROUTERS.indexOf(this), 1);
	}

	navigateTo(url) {
		let routeView = getMatchingChildren(this.kids,url)[0];
		if(routeView) {
			console.log("匹配到了");
			this.mypath = routeView[1].path;
			lineventArt(this.mypath);
			this.componentUpdate({
				routeView: routeView, 
			});
		  return true;
		}
	  }

    //渲染输出
	render() {
		return <div>{this.routeView}</div>;
	}
}





//Link 组件
const StaticLink = (props, kids) =>{ 
	//组件参数解释: props 是一个object，存储了所有的参数，kids是一个数组，存储了所有的children
	//新创建一个vnode, type: [0]:'a' , props: [1]: += onClick, kids: [2]: kids 
	//简单说，就是建一个a链接，继承原有的path路径和链接名称，添加一个点击事件
	return JSX('a', assign({onClick: handleLinkClick}, props), kids);
};





class Link extends Element{
	myclassName;
	this(props, kids) { 
		this.url = props.href;
		this.kids = kids;
		this.props = props ;
	  }
	
    
	// 加载成功后
	componentDidMount() {
		Subscribers.push(this);
	}

	//按键回调
	selectenev(path){
		let  matches = ( exec(this.url, path, {}) !== false );
		let myclassName = [this.props.class || this.props.className, matches && this.props.activeClassName].filter(Boolean).join(' ');
		this.componentUpdate({myclassName, 

		});
		return true;
		  
	}





	// 当前router析构以后
	componentWillUnmount() {
		Subscribers.splice(Subscribers.indexOf(this), 1);
	}
    
	render() {
		return  <StaticLink href={this.url}  class={this.myclassName} >{this.kids}</StaticLink>
             
	}
}




































const Route = props => JSX(props.component, props);




export {  Router,  Link};
export default Router;